package server.core;

import server.*;
import server.connector.http.HttpRequestImpl;
import server.connector.http.HttpResponseImpl;
import server.util.LifecycleSupport;

import javax.servlet.ServletException;
import java.io.IOException;
import java.util.HashMap;

public class SimpleContext implements Container, Lifecycle {
    //存放名字,名字对应的wrapper
    protected HashMap<String, Container> children = new HashMap<>();
    //加载器
    protected SimpleLoader loader = null;
    //管道
    protected SimplePipeline pipeline = new SimplePipeline(this);
    //请求路径,wrapper名对应表
    protected HashMap<String, String> servletMappings = new HashMap<>();
    //映射器
    protected Mapper mapper = null;
    //协议,Mapper对应表
    protected HashMap<String, Mapper> mappers = new HashMap<>();
    //父容器
    private Container parent = null;
    //是否启动
    protected boolean started = false;
    //日志器
    private Logger logger = null;

    protected LifecycleSupport lifecycle = new LifecycleSupport(this);

    public SimpleContext() {
        pipeline.setBasic(new SimpleContextValve());
    }

    //添加路径-wrapper名对
    public void addServletMapping(String pattern, String name) {
        synchronized (servletMappings) {
            servletMappings.put(pattern, name);
        }
    }
    //根据路径返回wrapper名
    public String findServletMapping(String pattern) {
        synchronized (servletMappings) {
            return servletMappings.get(pattern);
        }
    }
    //添加子容器
    public void addChild(Container child) {
        child.setParent(this);
        children.put(child.getName(), child);
    }
    //添加映射器
    public void addMapper(Mapper mapper) {
        // this method is adopted from addMapper in ContainerBase
        // the first mapper added becomes the default mapper
        mapper.setContainer(this);
        this.mapper = mapper;
        synchronized(mappers) {
            if (mappers.get(mapper.getProtocol()) != null)
                throw new IllegalArgumentException("addMapper:  Protocol '" +
                        mapper.getProtocol() + "' is not unique");
            mapper.setContainer(this);      // May throw IAE
            mappers.put(mapper.getProtocol(), mapper);
            if (mappers.size() == 1)
                this.mapper = mapper;
            else
                this.mapper = null;
        }
    }
    public Container findChild(String name) {
        if (name == null)
            return null;
        synchronized (children) {       // Required by post-start changes
            return children.get(name);
        }
    }
    public Container[] findChildren() {
        synchronized (children) {
            Container results[] = new Container[children.size()];
            return children.values().toArray(results);
        }
    }
    //找到映射器
    public Mapper findMapper(String protocol) {
        // the default mapper will always be returned, if any,
        // regardless the value of protocol
        if (mapper != null)
            return mapper;
        else
            synchronized (mappers) {
                return mappers.get(protocol);
            }
    }
    public void invoke(HttpRequestImpl request, HttpResponseImpl response)
            throws IOException, ServletException {
        pipeline.invoke(request, response);
    }

    @Override
    public String getName() {
        return null;
    }

    @Override
    public void setParent(Container container) {

    }

    //根据路径返回容器
    public Container map(HttpRequestImpl request, boolean update) {
        //this method is taken from the map method in org.apache.cataline.core.ContainerBase
        //the findMapper method always returns the default mapper, if any, regardless the
        //request's protocol
        Mapper mapper = findMapper(request.getProtocol());
        if (mapper == null)
            return null;
        // Use this Mapper to perform this mapping
        return mapper.map(request, update);
    }
    public synchronized void addValve(Valve valve) {
        pipeline.addValve(valve);
    }
    //getter-----------------------------------------------------------
    public Logger getLogger() {
        return logger;
    }
    //获取加载器
    @Override
    public SimpleLoader getLoader() {
        if (loader != null)
            return loader;
        if (parent != null)
            return parent.getLoader();
        return null;
    }
    public Valve getBasic() {
        return pipeline.getBasic();
    }

    public Valve[] getValves() {
        return pipeline.getValves();
    }
    //setter-----------------------------------------------------------
    public void setBasic(Valve valve) {
        pipeline.setBasic(valve);
    }
    public void setLoader(SimpleLoader loader) {
        this.loader = loader;
    }
    public void setLogger(Logger logger) {
        this.logger = logger;
    }
    //实现Lifecycle接口-------------------------------------------------

    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }

    @Override
    public LifecycleListener[] findLifecycleListeners() {
        return lifecycle.findLifecycleListeners();
    }

    @Override
    public void removeLifecycleListener(LifecycleListener listener) {
        lifecycle.removeLifecycleListener(listener);
    }

    @Override
    public void start() throws LifecycleException {
        log("starting Context");
        if(started)
            throw new LifecycleException("SimpleContext has already started");
        //触发启动前事件
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
        started = true;
        try {
            //启动加载器
            if(loader != null && loader instanceof Lifecycle) {
                ((Lifecycle)loader).start();
            }
            //启动子容器
            Container[] children = findChildren();
            for (Container container : children) {
                if (container instanceof Lifecycle) {
                    ((Lifecycle)container).start();
                }
            }
            //启动管道
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).start();
            }
            //触发启动事件
            lifecycle.fireLifecycleEvent(START_EVENT, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //触发启动后事件
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
        log("Context started");
    }

    @Override
    public void stop() throws LifecycleException {
        log("stopping Context");
        if (!started)
            throw new LifecycleException("SimpleContext has not been started");
        //触发关闭前事件
        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
        //触发关闭事件
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
        started = false;
        try {
            //关闭管道
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).stop();
            }
            //关闭子容器
            Container[] children = findChildren();
            for (Container container : children) {
                if (container instanceof Lifecycle) {
                    ((Lifecycle) container).stop();
                }
            }
            //关闭加载器
            if (loader != null && loader instanceof Lifecycle) {
                ((Lifecycle) loader).stop();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //触发关闭后事件
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
        log("Context stopped");
    }

    private void log(String message) {
        Logger logger = this.getLogger();
        if (logger!=null)
            logger.log(message);
    }
}
